package org.dromara.exam.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.exception.base.BaseException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.exam.domain.dto.ProjectSetting;
import org.dromara.exam.domain.dto.TemplateSchema;
import org.dromara.exam.domain.entity.ExamAnswer;
import org.dromara.exam.domain.entity.ExamProject;
import org.dromara.exam.domain.bo.ExamAnswerBo;
import org.dromara.exam.domain.bo.ExamProjectBo;
import org.dromara.exam.domain.vo.*;
import org.dromara.exam.mapper.ExamProjectMapper;
import org.dromara.exam.service.*;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 项目Service业务层处理
 *
 * @author xiyin321
 * @date 2024-05-17
 */
@RequiredArgsConstructor
@Service
public class ExamProjectServiceImpl implements IExamProjectService {

    private final ExamProjectMapper baseMapper;
    private final IExamAnswerService answerService;
    private final IExamTemplateService templateService;


    /**
     * 查询项目
     */
    @Override
    public ExamProjectVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询项目列表
     */
    @Override
    public TableDataInfo<ExamProjectVo> queryPage(ExamProjectBo bo, PageQuery pageQuery) {
        Page<ExamProjectVo> result = baseMapper.selectPageProjectList(pageQuery.build(), this.buildPaperQueryWrapper(bo));
        if (result.getTotal() == 0) {
            return TableDataInfo.build(result);
        }
        List<Long> ids = result.getRecords().stream().map(ExamProjectVo::getId).toList();
        List<ExamProjectVo> counts = answerService.queryAnswerCountByPaperIds(ids);
        result.getRecords().forEach(project -> {
            project.setCount(counts.stream().filter(count -> count.getId().equals(project.getId())).findFirst().orElse(new ExamProjectVo()).getCount());
        });
        return TableDataInfo.build(result);
    }

    /**
     * 根据当前用户ID查询答卷关联的项目分页列表
     *
     * @return
     */
    @Override
    public TableDataInfo<ExamProjectVo> queryProjectsPageByUserId(ExamProjectBo bo, PageQuery pageQuery) {
        Long userId = LoginHelper.getUserId();
        Map<String, Object> params = bo.getParams();
        QueryWrapper<ExamProject> wrapper = Wrappers.query();
        wrapper.eq("del_flag", "0")
            .eq(ObjectUtils.isNotNull(bo.getStatus()), "p.status", bo.getStatus())
            .between(params.get("beginTime") != null && params.get("endTime") != null,
                "p.create_time", params.get("beginTime"), params.get("endTime"))
            .groupBy("project_id")
            .orderByDesc("p.status", "p.create_time");
        Page<ExamProjectVo> result = baseMapper.selectProjectsPageByUserId(userId, pageQuery.build(), wrapper);
        return TableDataInfo.build(result);
    }

    /*构建项目列表查询对象*/
    private Wrapper<ExamProject> buildPaperQueryWrapper(ExamProjectBo bo) {
        QueryWrapper<ExamProject> wrapper = Wrappers.query();
        wrapper.eq("p.del_flag", "0")
            .like(StringUtils.isNotBlank(bo.getName()), "p.name", bo.getName())
            .eq(ObjectUtils.isNotNull(bo.getMode()), "p.mode", bo.getMode())
            .eq(StringUtils.isNotBlank(bo.getStatus()), "p.status", bo.getStatus())
            .orderByDesc("p.create_time");
        return wrapper;
    }

    /**
     * 查询项目列表
     */
    @Override
    public List<ExamProjectVo> queryList(ExamProjectBo bo) {
        LambdaQueryWrapper<ExamProject> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<ExamProject> buildQueryWrapper(ExamProjectBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<ExamProject> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getName()), ExamProject::getName, bo.getName());
        lqw.eq(ObjectUtils.isNotNull(bo.getMode()), ExamProject::getMode, bo.getMode());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), ExamProject::getStatus, bo.getStatus());
        return lqw;
    }

    /**
     * 新增项目
     *
     * @return 返回新添加的项目对象
     */
    @Override
    public ExamProjectVo insertByBo(ExamProjectBo bo) {
        bo.setId(IdWorker.getId());
        bo.getSurvey().setId(String.valueOf(bo.getId()));
        bo.getSurvey().setTitle(bo.getName());
        bo.getSurvey().setType(bo.getMode());
        ExamProject add = MapstructUtils.convert(bo, ExamProject.class);
        validEntityBeforeSave(add);
        /*添加数据成功后获取添加的数据*/
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            return this.queryById(add.getId());
        }
        return null;
    }

    /**
     * 修改项目
     */
    @Override
    public Boolean updateByBo(ExamProjectBo bo) {
        bo.getSurvey().setTitle(bo.getName());
        bo.getSurvey().getChildren().forEach(item -> {
            if (StringUtils.isBlank(item.getId())) {
                item.setId(String.valueOf(IdWorker.getId()));
            }
        });
        ExamProject update = MapstructUtils.convert(bo, ExamProject.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(ExamProject entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除项目
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /*发布项目*/
    @Override
    public Boolean publishProject(Long id) {
        /*将发布状态设置为发布*/
        LambdaUpdateWrapper<ExamProject> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(ExamProject::getId, id).set(ExamProject::getStatus, "1");
        return baseMapper.update(null, wrapper) > 0;
    }

    /*取消发布项目*/
    @Override
    public Boolean cancelPublishProject(Long id) {
        /*将发布状态设置为未发布*/
        LambdaUpdateWrapper<ExamProject> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(ExamProject::getId, id).set(ExamProject::getStatus, "0");
        // 处理停止项目下的答卷
        answerService.submitAnswerByProjectId(id);
        return baseMapper.update(null, wrapper) > 0;
    }

    /**
     * 项目重命名
     *
     * @param bo
     * @return
     */
    @Override
    public Boolean updateName(ExamProjectBo bo) {
        LambdaUpdateWrapper<ExamProject> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(ExamProject::getId, bo.getId()).set(ExamProject::getName, bo.getName());
        return baseMapper.update(null, wrapper) > 0;
    }

    /*计算总分*/
    private Double calculateScore(ExamProjectBo bo) {
        Double examScore = 0.0;
        /*获取编辑器总分*/
        for (TemplateSchema item : bo.getSurvey().getChildren()) {
            examScore += item.getAttribute().getExamScore();
        }
        /*获取题库总分*/
        if (bo.getSetting().getExamSetting().getRandomProject() != null) {
            for (ProjectSetting.RandomQuestionCondition item : bo.getSetting().getExamSetting().getRandomProject()) {
                Long num = 0L;
                /*如果题目数量为null,则导入全部题目，查询题目数量*/
                if (item.getNum() == null || item.getNum() == 0) {
                    num = templateService.queryTemplateCountByRepoId(item.getRepoId());
                } else {
                    num = Long.valueOf(item.getNum());
                }
                if (item.getScore() == null) {
                    Long[] ids = new Long[]{item.getRepoId()};
                    List<ExamTemplateVo> questionVos = templateService.queryListByIds(ids);
                    for (ExamTemplateVo questionVo : questionVos) {
                        examScore += questionVo.getScore();
                    }
                } else {
                    examScore += item.getScore() * num;
                }
            }
        }
        return examScore;
    }

    /*预览项目*/
    @Override
    public PublicPaperVo queryViewById(Long id) {
        ExamProjectVo paperVo = baseMapper.selectVoById(id);
        return BeanUtil.copyProperties(paperVo, PublicPaperVo.class);
    }

    /*校验项目配置*/
    private void validatePaper(ExamProjectVo paperVo) {
        ProjectSetting setting = paperVo.getSetting();
        ProjectSetting.ExamSetting examSetting = paperVo.getSetting().getExamSetting();

        // 校验考试开始时间
        if (examSetting.getStartTime() != null && examSetting.getStartTime().compareTo(new Date()) > 0) {
            throw new BaseException("考试未开始");
        }
        // 校验考试结束时间
        if (examSetting.getEndTime() != null && examSetting.getEndTime().compareTo(new Date()) < 0) {
            throw new BaseException("考试已结束");
        }
    }
}
